package io.xxx.cyb.sync.impl

import com.alibaba.fastjson.JSONObject
import io.xxx.cyb.model.Document
import io.xxx.cyb.model.Store
import io.xxx.cyb.sync.Porter
import io.xxx.cyb.util.dateTimeFormatter
import io.xxx.cyb.util.toJSONString
import io.xxx.cyb.util.toLocalDateTime
import org.apache.commons.codec.digest.DigestUtils
import org.springframework.web.util.UriComponentsBuilder
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

/**
 * 宝宝树
 *
 * http://platform.meitun.com/apidoc/
 */
abstract class BbsPagePorter(sid: String) : Porter(sid) {

    private val httpUrl = "http://platform.meitun.com"

    protected abstract val path: String

    protected fun getResponse(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        timeRange: Any?,
        pageNo: Long = 1
    ): JSONObject {
        val timestamp = LocalDateTime.now().format(formatter)
        val apiVersion = "v6.0"
        val sign = DigestUtils.md5Hex(store.appKey + store.accessToken + timestamp + apiVersion).uppercase()
        val url = UriComponentsBuilder.fromHttpUrl(httpUrl)
            .path(path)
            .queryParam("appkey", store.appKey)
            .queryParam("version", apiVersion)
            .queryParam("timestamp", timestamp)
            .queryParam("sign", sign)
            .toUriString()
        val request = buildRequest(startTime, endTime, timeRange as String, pageNo)
        val response = restTemplate.postForEntity(url, request.toJSONString(), JSONObject::class.java).body!!
        if (!response.getBoolean("isSuccess")) {
            throwException(
                javaClass.simpleName,
                path,
                response.getString("errorCode"),
                response.getString("errorMessage")
            )
        }
        return response.getJSONObject("data")
    }

    protected abstract fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        timeRange: String,
        pageNo: Long = 1
    ): Map<String, String>

    companion object {
        private val formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
    }
}

@Suppress("unused")
open class BbsTradePorter(sid: String) : BbsPagePorter(sid) {

    override val path = "/order/orderInPage"

    override fun getParameters(store: Store): Pair<List<Any>, Boolean> {
        return listOf("modified_time") to false
    }

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long? {
        val response = getResponse(store, startTime, endTime, parameter)
        return response.getLong("totalCount")
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long,
    ): List<Document> {
        val response = getResponse(store, startTime, endTime, parameter, pageNo)
        val list = response.getJSONArray("list")
        return list.map {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            val modified = value.getLong("payTime").toLocalDateTime() ?: value.getLong("createTime").toLocalDateTime()
            Document(value.getString("code"), value, modified)
        }
    }

    override fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        timeRange: String,
        pageNo: Long
    ): Map<String, String> {
        return mapOf(
            "timeRange" to timeRange,
            "startTime" to startTime.format(dateTimeFormatter),
            "endTime" to endTime.format(dateTimeFormatter),
            "pageNo" to pageNo.toString(),
            "pageSize" to pageSize.toString(),
        )
    }
}

@Suppress("unused")
class BbsTradeProcurator(sid: String) : BbsTradePorter(sid) {

    override val cron = "0/10 * * * * ?"

    override fun getParameters(store: Store): Pair<List<Any>, Boolean> {
        return listOf("create_time") to false
    }
}